﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.ModelBinding;
using Cnm.Core;
using Cnm.Core.Domain.Localization;
using Cnm.Models;
using Cnm.Mvc.Web.Framework.Localization;
using Cnm.Servicers.Localization;

namespace Cnm.Mvc.Web.Framework
{
    /// <summary>
    /// Work context for web application
    /// </summary>
    public partial class WebWorkContext : IWorkContext
    {
        #region Fields

        private readonly HttpContextBase _httpContext;
        private readonly ILanguageService _languageService;
        private readonly LocalizationSettings _localizationSettings;

        private Language _cachedLanguage;
        private string currentLanguageSessionKey = "CurrentLanguage";
        static Dictionary<string, CultureInfo> SupportedCultures { get; set; }

        #endregion

        #region Ctor

        public WebWorkContext(HttpContextBase httpContext,
            ILanguageService languageService,
            LocalizationSettings localizationSettings)
        {
            this._httpContext = httpContext;
            this._languageService = languageService;
            this._localizationSettings = localizationSettings;

            InitializeSupportedCultures();
        }

        #endregion

        #region Utilities

        protected virtual Language GetLanguageFromUrl()
        {
            if (_httpContext == null || _httpContext.Request == null)
                return null;

            string virtualPath = _httpContext.Request.AppRelativeCurrentExecutionFilePath;
            string applicationPath = _httpContext.Request.ApplicationPath;
            if (!virtualPath.IsLocalizedUrl(applicationPath, false))
                return null;

            var seoCode = virtualPath.GetLanguageSeoCodeFromUrl(applicationPath, false);
            if (String.IsNullOrEmpty(seoCode))
                return null;

            var language = _languageService
                .GetAllLanguages()
                .FirstOrDefault(l => seoCode.Equals(l.UniqueSeoCode, StringComparison.InvariantCultureIgnoreCase));
            if (language != null && language.Published != null && (bool) language.Published)
            {
                return language;
            }

            return null;
        }

        protected virtual Language GetLanguageFromBrowserSettings()
        {
            if (_httpContext == null ||
                _httpContext.Request == null ||
                _httpContext.Request.UserLanguages == null)
                return null;

            var userLanguage = _httpContext.Request.UserLanguages.FirstOrDefault();
            if (String.IsNullOrEmpty(userLanguage))
                return null;

            var language = _languageService
                .GetAllLanguages()
                .FirstOrDefault(l => userLanguage.Equals(l.LanguageCulture, StringComparison.InvariantCultureIgnoreCase));
            if (language != null && language.Published != null && (bool)language.Published)
            {
                return language;
            }

            return null;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Get or set current user working language
        /// </summary>
        public virtual Language WorkingLanguage
        {
            get
            {
                if (_cachedLanguage != null)
                    return _cachedLanguage;

                Language detectedLanguage = null;
                if (_localizationSettings.SeoFriendlyUrlsForLanguagesEnabled)
                {
                    //get language from URL
                    detectedLanguage = GetLanguageFromUrl();
                }
                if (detectedLanguage != null && _httpContext.Session != null)
                {
                    CultureInfo cultureInfo = GetCulture(detectedLanguage.UniqueSeoCode);
                    Thread.CurrentThread.CurrentUICulture = cultureInfo;
                    Thread.CurrentThread.CurrentCulture = cultureInfo;
                }

                var allLanguages = _languageService.GetAllLanguages();
                //find current customer language
                var language = GetLanguage(CultureInfo.DefaultThreadCurrentCulture);
                if (language == null)
                {
                    //it not specified, then return the first (filtered by current store) found one
                    language = allLanguages.FirstOrDefault();
                }
                if (language == null)
                {
                    //it not specified, then return the first found one
                    language = _languageService.GetAllLanguages().FirstOrDefault();
                }

                if (language != null)
                {
                    //cache
                    _cachedLanguage = language;
                    return _cachedLanguage;
                }
                else
                {
                    return new Language
                    {
                        Id = 0
                    };
                }
            }
            set
            {
                CultureInfo cultureInfo = GetCulture(value.UniqueSeoCode);
                CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
                CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;
                //reset cache
                _cachedLanguage = null;
            }
        }

        /// <summary>
        /// Get or set value indicating whether we're in admin area
        /// </summary>
        public virtual bool IsAdmin { get; set; }

        void AddSupportedCulture(string name)
        {
            SupportedCultures.Add(name, CultureInfo.CreateSpecificCulture(name));
        }

        void InitializeSupportedCultures()
        {
            SupportedCultures = new Dictionary<string, CultureInfo>();
            foreach (var allLanguage in _languageService.GetAllLanguages())
            {
                AddSupportedCulture(allLanguage.UniqueSeoCode);
            }
        }

        string ConvertToShortForm(string code)
        {
            return code.Substring(0, 2);
        }

        bool CultureIsSupported(string code)
        {
            if (string.IsNullOrWhiteSpace(code))
                return false;
            code = code.ToLowerInvariant();
            if (code.Length == 2)
                return SupportedCultures.ContainsKey(code);
            return CultureFormatChecker.FormattedAsCulture(code) && SupportedCultures.ContainsKey(ConvertToShortForm(code));
        }

        public static CultureInfo DefaultCulture
        {
            get
            {
                return SupportedCultures.FirstOrDefault().Value;
            }
        }

        CultureInfo GetCulture(string code)
        {
            if (!CultureIsSupported(code))
                return DefaultCulture;
            string shortForm = ConvertToShortForm(code).ToLowerInvariant();
            return SupportedCultures[shortForm];
        }

        private Language GetLanguage(CultureInfo cultureInfo)
        {
            if (cultureInfo != null)
                return _languageService.GetAllLanguages()
                    .FirstOrDefault(p => p.UniqueSeoCode == cultureInfo.TwoLetterISOLanguageName);

            return null;
        }

        #endregion
    }
}
